//
//  IMLogUtilsTests.m
//  DualMediationSDK
//
//  Created by YeJary on 2025/6/23.
//

#import <XCTest/XCTest.h>
#import <DualMediationSDK/IMLogUtils.h>
#import <mach/mach.h>
#import <mach/task.h>
#import <mach/mach_host.h>

@interface IMLogUtilsTests : XCTestCase

@property (nonatomic, strong) IMLogConfig *testConfig;
@property (nonatomic, strong) NSString *testLogDirectory;

@end

@implementation IMLogUtilsTests

#pragma mark - Setup & Teardown

- (void)setUp {
    [super setUp];
    
    // 设置测试用的日志目录
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsPath = [paths firstObject];
    self.testLogDirectory = [documentsPath stringByAppendingPathComponent:@"IMLogUtilsTests"];
    
    // 创建测试配置
    self.testConfig = [[IMLogConfig alloc] init];
    self.testConfig.level = IMLogLevelVerbose;
    self.testConfig.enableConsoleLog = NO; // 测试时关闭控制台输出
    self.testConfig.enableFileLog = YES;
    self.testConfig.logDirectory = self.testLogDirectory;
    self.testConfig.maxFileSize = 1024 * 1024; // 1MB for testing
    self.testConfig.maxFileCount = 3;
//    self.testConfig.retentionDays = 1;
    self.testConfig.enableSensitiveFilter = YES;
    
    // 初始化日志系统
    [IMLogUtils initWithConfig:self.testConfig];
    
    NSLog(@"[TEST SETUP] 测试环境初始化完成，日志目录: %@", self.testLogDirectory);
}

- (void)tearDown {
    // 清理测试文件
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:self.testLogDirectory]) {
        NSError *error;
        [fileManager removeItemAtPath:self.testLogDirectory error:&error];
        if (error) {
            NSLog(@"[TEST TEARDOWN] 清理测试目录失败: %@", error.localizedDescription);
        }
    }
    
    [super tearDown];
}

#pragma mark - 基础功能测试

- (void)testLogLevels {
    // 测试所有日志级别
    [IMLogUtils verbose:IMLogTagGeneral format:@"[TEST] Verbose level test"];
    [IMLogUtils debug:IMLogTagGeneral format:@"[TEST] Debug level test"];
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] Info level test"];
    [IMLogUtils warning:IMLogTagGeneral format:@"[TEST] Warning level test"];
    [IMLogUtils error:IMLogTagGeneral format:@"[TEST] Error level test"];
    
    // 等待异步写入完成
    [self waitForLogFileUpdate];
    
    // 验证日志文件是否创建
    NSString *currentLogFile = [IMLogUtils currentLogFilePath];
    XCTAssertNotNil(currentLogFile, @"日志文件应该被创建");
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    XCTAssertTrue([fileManager fileExistsAtPath:currentLogFile], @"日志文件应该存在");
    
    // 验证文件内容包含测试日志
    NSString *logContent = [IMLogUtils getLogFileContent:currentLogFile];
    XCTAssertNotNil(logContent, @"应该能够读取日志内容");
    XCTAssertTrue([logContent containsString:@"Verbose level test"], @"日志内容应该包含Verbose测试");
    XCTAssertTrue([logContent containsString:@"Error level test"], @"日志内容应该包含Error测试");
}

- (void)testLogConfiguration {
    // 测试日志级别动态调整
    IMLogLevel originalLevel = [IMLogUtils currentLogLevel];
    
    // 设置为Error级别
    [IMLogUtils setLogLevel:IMLogLevelError];
    XCTAssertEqual([IMLogUtils currentLogLevel], IMLogLevelError, @"日志级别应该被正确设置");
    
    // 写入不同级别的日志
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] Info should not appear"];
    [IMLogUtils error:IMLogTagGeneral format:@"[TEST] Error should appear"];
    
    [self waitForLogFileUpdate];
    
    NSString *logContent = [IMLogUtils getLogFileContent:[IMLogUtils currentLogFilePath]];
    XCTAssertFalse([logContent containsString:@"Info should not appear"], @"Info级别日志不应该出现");
    XCTAssertTrue([logContent containsString:@"Error should appear"], @"Error级别日志应该出现");
    
    // 恢复原始级别
    [IMLogUtils setLogLevel:originalLevel];
    
    // 测试日志开关
    [IMLogUtils enableLog:NO];
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] This should not appear when disabled"];
    
    [IMLogUtils enableLog:YES];
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] This should appear when enabled"];
    
    [self waitForLogFileUpdate];
    
    logContent = [IMLogUtils getLogFileContent:[IMLogUtils currentLogFilePath]];
    XCTAssertFalse([logContent containsString:@"should not appear when disabled"], @"禁用时的日志不应该出现");
    XCTAssertTrue([logContent containsString:@"should appear when enabled"], @"启用时的日志应该出现");
}

- (void)testFileManagement {
    // 测试文件创建和基础信息获取
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] File management test"];
    [self waitForLogFileUpdate];
    
    // 测试获取当前文件路径
    NSString *currentFile = [IMLogUtils currentLogFilePath];
    XCTAssertNotNil(currentFile, @"应该能获取当前日志文件路径");
    
    // 测试获取所有文件列表
    NSArray *allFiles = [IMLogUtils allLogFilePaths];
    XCTAssertNotNil(allFiles, @"应该能获取日志文件列表");
    XCTAssertGreaterThan(allFiles.count, 0, @"应该至少有一个日志文件");
    
    // 测试文件大小统计
    NSUInteger totalSize = [IMLogUtils totalLogFileSize];
    XCTAssertGreaterThan(totalSize, 0, @"日志文件总大小应该大于0");
    
    // 测试文件内容读取
    NSString *content = [IMLogUtils getLogFileContent:currentFile];
    XCTAssertNotNil(content, @"应该能读取文件内容");
    XCTAssertTrue([content containsString:@"File management test"], @"文件内容应该包含测试日志");
}

- (void)testSpecialLogMethods {
    // 测试广告事件日志
    [IMLogUtils logAdEvent:@"test_ad_request" 
                  adUnitId:@"test_banner_001" 
                    params:@{
                        @"placement": @"test_placement",
                        @"format": @"banner",
                        @"size": @"320x50"
                    }];
    
    [IMLogUtils logAdEvent:@"test_ad_show" 
                  adUnitId:@"test_banner_001" 
                    params:@{
                        @"revenue": @0.05,
                        @"currency": @"USD",
                        @"network": @"TestNetwork"
                    }];
    
    // 测试网络请求日志
    [IMLogUtils logNetworkRequest:@"https://test-api.example.com/ads" 
                           method:@"POST" 
                       statusCode:200 
                         duration:0.156];
    
    // 测试性能日志
    [IMLogUtils logPerformance:@"test_ad_load_time" value:1.23 unit:@"seconds"];
    [IMLogUtils logPerformance:@"test_memory_usage" value:45.6 unit:@"MB"];
    
    // 测试用户行为日志
    [IMLogUtils logUserAction:@"test_button_click" 
                       params:@{
                           @"button_id": @"test_button",
                           @"screen": @"main_screen"
                       }];
    
    [self waitForLogFileUpdate];
    
    // 验证特殊日志方法产生的内容
    NSString *logContent = [IMLogUtils getLogFileContent:[IMLogUtils currentLogFilePath]];
    XCTAssertTrue([logContent containsString:@"test_ad_request"], @"广告事件日志应该被记录");
    XCTAssertTrue([logContent containsString:@"test-api.example.com"], @"网络请求日志应该被记录");
    XCTAssertTrue([logContent containsString:@"test_ad_load_time"], @"性能日志应该被记录");
    XCTAssertTrue([logContent containsString:@"test_button_click"], @"用户行为日志应该被记录");
}

- (void)testSensitiveInfoFilter {
    // 测试敏感信息过滤功能
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] Login info: username=testuser, password=123456789"];
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] API call: token=abc123def456ghi789"];
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] Config: api_key=\"secret_key_value\""];
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] User info: phone=13812345678"];
    [IMLogUtils info:IMLogTagGeneral format:@"[TEST] Payment: card_number=6225881234567890"];
    
    [self waitForLogFileUpdate];
    
    NSString *logContent = [IMLogUtils getLogFileContent:[IMLogUtils currentLogFilePath]];
    
    // 验证敏感信息被正确过滤
    XCTAssertFalse([logContent containsString:@"123456789"], @"密码应该被过滤");
    XCTAssertFalse([logContent containsString:@"abc123def456ghi789"], @"Token应该被过滤");
    XCTAssertFalse([logContent containsString:@"secret_key_value"], @"API密钥应该被过滤");
    XCTAssertFalse([logContent containsString:@"13812345678"], @"手机号应该被过滤");
    XCTAssertFalse([logContent containsString:@"6225881234567890"], @"银行卡号应该被过滤");
    
    // 验证过滤标记存在
    XCTAssertTrue([logContent containsString:@"***"], @"应该包含过滤标记");
}

- (void)testErrorHandling {
    // 使用@try-@catch替代XCTAssertNoThrow，避免语法错误
    BOOL didNotCrash = YES;
    
    // 测试nil参数处理
    @try {
        [IMLogUtils info:IMLogTagGeneral format:nil];
    } @catch (NSException *exception) {
        didNotCrash = NO;
    }
    XCTAssertTrue(didNotCrash, @"nil格式字符串不应该崩溃");
    
    didNotCrash = YES;
    @try {
        [IMLogUtils logAdEvent:nil adUnitId:nil params:nil];
    } @catch (NSException *exception) {
        didNotCrash = NO;
    }
    XCTAssertTrue(didNotCrash, @"nil参数不应该崩溃");
    
    didNotCrash = YES;
    @try {
        [IMLogUtils logNetworkRequest:nil method:nil statusCode:0 duration:0];
    } @catch (NSException *exception) {
        didNotCrash = NO;
    }
    XCTAssertTrue(didNotCrash, @"nil参数不应该崩溃");
    
    // 测试空字符串
    didNotCrash = YES;
    @try {
        [IMLogUtils info:IMLogTagGeneral format:@""];
        [IMLogUtils logAdEvent:@"" adUnitId:@"" params:@{}];
    } @catch (NSException *exception) {
        didNotCrash = NO;
    }
    XCTAssertTrue(didNotCrash, @"空字符串不应该崩溃");
    
    // 测试循环引用对象
    NSMutableDictionary *dict1 = [NSMutableDictionary dictionary];
    NSMutableDictionary *dict2 = [NSMutableDictionary dictionary];
    dict1[@"ref"] = dict2;
    dict2[@"ref"] = dict1;
    
    didNotCrash = YES;
    @try {
        [IMLogUtils info:IMLogTagGeneral format:@"[TEST] Circular reference: %@", dict1];
    } @catch (NSException *exception) {
        didNotCrash = NO;
    }
    XCTAssertTrue(didNotCrash, @"循环引用对象不应该崩溃");
}

#pragma mark - 性能测试

- (void)testPerformance {
    [self measureBlock:^{
        // 测试批量写入性能
        for (NSInteger i = 0; i < 100; i++) {
            [IMLogUtils info:IMLogTagPerformance format:@"[PERF TEST] Performance test log #%ld", (long)i];
        }
        
        // 等待异步写入完成
        [self waitForLogFileUpdate];
    }];
}

- (void)testConcurrency {
    XCTestExpectation *concurrencyExpectation = [self expectationWithDescription:@"Concurrency test"];
    
    dispatch_group_t group = dispatch_group_create();
    NSInteger threadCount = 5;
    NSInteger logsPerThread = 20;
    
    for (NSInteger i = 0; i < threadCount; i++) {
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSInteger j = 0; j < logsPerThread; j++) {
                [IMLogUtils info:IMLogTagGeneral format:@"[CONCURRENCY TEST] Thread%ld Log%ld", (long)i, (long)j];
            }
        });
    }
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        [self waitForLogFileUpdate];
        
        // 验证并发写入结果
        NSString *logContent = [IMLogUtils getLogFileContent:[IMLogUtils currentLogFilePath]];
        NSInteger expectedLogCount = threadCount * logsPerThread;
        NSInteger actualLogCount = 0;
        
        NSArray *lines = [logContent componentsSeparatedByString:@"\n"];
        for (NSString *line in lines) {
            if ([line containsString:@"CONCURRENCY TEST"]) {
                actualLogCount++;
            }
        }
        
        XCTAssertEqual(actualLogCount, expectedLogCount, @"并发写入的日志数量应该正确");
        [concurrencyExpectation fulfill];
    });
    
    [self waitForExpectationsWithTimeout:10.0 handler:nil];
}

- (void)testMemoryUsage {
    // 获取测试前内存使用
    vm_size_t memoryBefore = [self getCurrentMemoryUsage];
    
    // 生成大量日志测试内存泄漏
    for (NSInteger i = 0; i < 500; i++) {
        NSString *testData = [NSString stringWithFormat:@"Memory test data #%ld - %@", (long)i, [NSDate date]];
        [IMLogUtils info:IMLogTagGeneral format:@"[MEMORY TEST] %@", testData];
    }
    
    [self waitForLogFileUpdate];
    
    // 获取测试后内存使用
    vm_size_t memoryAfter = [self getCurrentMemoryUsage];
    vm_size_t memoryDiff = memoryAfter - memoryBefore;
    
    // 验证内存增长在合理范围内（小于10MB）
    vm_size_t maxAcceptableIncrease = 10 * 1024 * 1024; // 10MB
    XCTAssertLessThan(memoryDiff, maxAcceptableIncrease, @"内存增长应该在合理范围内");
    
    NSLog(@"[MEMORY TEST] Memory usage - Before: %.2fMB, After: %.2fMB, Diff: %.2fMB", 
          memoryBefore / (1024.0 * 1024.0), 
          memoryAfter / (1024.0 * 1024.0), 
          memoryDiff / (1024.0 * 1024.0));
}

#pragma mark - 文件轮转测试

- (void)testFileRotation {
    // 设置较小的文件大小以触发轮转
    self.testConfig.maxFileSize = 1024; // 1KB
    [IMLogUtils initWithConfig:self.testConfig];
    
    NSString *longMessage = [@"" stringByPaddingToLength:200 withString:@"A" startingAtIndex:0];
    
    // 写入足够多的日志以触发文件轮转
    for (NSInteger i = 0; i < 10; i++) {
        [IMLogUtils info:IMLogTagGeneral format:@"[FILE ROTATION TEST] %@ #%ld", longMessage, (long)i];
    }
    
    [self waitForLogFileUpdate];
    
    // 验证是否创建了多个文件
    NSArray *allFiles = [IMLogUtils allLogFilePaths];
    XCTAssertGreaterThan(allFiles.count, 1, @"应该创建多个日志文件");
    
    // 验证每个文件的大小都在合理范围内
    for (NSString *filePath in allFiles) {
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSError *error;
        NSDictionary *attributes = [fileManager attributesOfItemAtPath:filePath error:&error];
        XCTAssertNil(error, @"获取文件属性不应该出错");
        
        unsigned long long fileSize = [attributes fileSize];
        XCTAssertLessThanOrEqual(fileSize, self.testConfig.maxFileSize * 2, @"文件大小应该在预期范围内");
    }
}

- (void)testLogTags {
    // 测试所有标签
    NSArray *testMessages = @[
        @"General message",
        @"SDK initialization",
        @"Ad request",
        @"Ad show",
        @"Ad click",
        @"Network operation",
        @"Cache operation",
        @"Banner ad",
        @"Interstitial ad",
        @"Rewarded ad",
        @"Native ad",
        @"Bidding process",
        @"Waterfall execution",
        @"Performance metric",
        @"Error occurred"
    ];
    
    IMLogTag tags[] = {
        IMLogTagGeneral,
        IMLogTagSDKInit,
        IMLogTagAdRequest,
        IMLogTagAdShow,
        IMLogTagAdClick,
        IMLogTagNetwork,
        IMLogTagCache,
        IMLogTagBanner,
        IMLogTagInterstitial,
        IMLogTagReward,
        IMLogTagNative,
        IMLogTagBidding,
        IMLogTagWaterfall,
        IMLogTagPerformance,
        IMLogTagError
    };
    
    // 写入不同标签的日志
    for (NSInteger i = 0; i < sizeof(tags)/sizeof(tags[0]); i++) {
        [IMLogUtils info:tags[i] format:@"[TAG TEST] %@", testMessages[i]];
    }
    
    [self waitForLogFileUpdate];
    
    // 验证所有标签的日志都被正确记录
    NSString *logContent = [IMLogUtils getLogFileContent:[IMLogUtils currentLogFilePath]];
    for (NSString *message in testMessages) {
        XCTAssertTrue([logContent containsString:message], @"日志应该包含标签测试消息: %@", message);
    }
}

#pragma mark - 辅助方法

- (void)waitForLogFileUpdate {
    // 等待异步日志写入完成
    XCTestExpectation *expectation = [self expectationWithDescription:@"Log file update"];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [expectation fulfill];
    });
    [self waitForExpectationsWithTimeout:2.0 handler:nil];
}

- (vm_size_t)getCurrentMemoryUsage {
    struct task_basic_info info;
    mach_msg_type_number_t size = TASK_BASIC_INFO_COUNT;
    kern_return_t result = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
    
    if (result == KERN_SUCCESS) {
        return info.resident_size;
    }
    return 0;
}

@end 
